package gld;

import static robocode.util.Utils.normalRelativeAngleDegrees;

import java.awt.Color;
import java.util.HashMap;
import java.util.Map;

import robocode.AdvancedRobot;
import robocode.RobotDeathEvent;
import robocode.ScannedRobotEvent;

public class HK47 extends AdvancedRobot {
	
	private Map<String, RobotModel> radarMap = new HashMap<String, RobotModel>();
	private double turningValue;
	private int turn = 0;
	private int lastAttackTurn = 0;
	private boolean lookForTarget;
	
	@Override
	public void run() {
		setBodyColor(Color.RED);
		setGunColor(Color.WHITE);
		setRadarColor(Color.WHITE);
		setScanColor(Color.RED);
		setBulletColor(Color.RED);
		
		setAdjustGunForRobotTurn(true);
		turningValue = 10;
		while(true) {
			if (lookForTarget) {
				turnGunRight(turningValue);
				if (turn - lastAttackTurn > 2) {
					turningValue = -10;
				}
				if (turn - lastAttackTurn > 5) {
					turningValue = 10;
				}
			}
			lookForTarget = !attack();
			turn++;
		}
	}
	
	private boolean attack() {
		boolean attacked = false;
		RobotModel target = null;
		for (RobotModel scanned : radarMap.values()) {
			if (turn - scanned.getLastTurnScanned() < 5) {
				target = scanned;
			}
		}
		
		if (target != null) {
			attacked = true;
			lastAttackTurn = turn;
			turningValue = normalRelativeAngleDegrees(target.getBearing() + (getHeading() - getRadarHeading()));
			if (target.getDistance() > 150) {
				setTurnGunRight(turningValue);
				setTurnRight(turningValue);
				setAhead(target.getDistance() - 140);
			} else if (target.getDistance() < 100) {
				if (target.getBearing() > -90 && target.getBearing() <= 90) {
					setBack(50);
				} else {
					setAhead(30);
				}
			} else {
				setTurnGunRight(turningValue);
				
			}
			setFire(3);
			execute();
			scan();
		}
		return attacked;
	}
	
	public double getTargetAbsoluteBearing(double targetBearingRadians, double headingRadians) {
		return targetBearingRadians + headingRadians;
	}
	
	public double getTargetLateralVelocity(double targetVelocity, double targetHeadingRadians, double targetAbsoluteBearing) {
		return targetVelocity * Math.sin(targetHeadingRadians - targetAbsoluteBearing);
	}
	
	public double getBulletSpeed(double bulletPower) {
		return 20 - bulletPower * 3;
	}
 
	public double maxEscapeAngle(double bulletPower) {
		return Math.asin(8 / getBulletSpeed(bulletPower));
	}
	
	public double getTargetLocationX(double targetAbsoluteBearing, double targetDistance, double x) {
		return x + Math.sin(targetAbsoluteBearing) * targetDistance;
	}
	
	public double getTargetLocationY(double targetAbsoluteBearing, double targetDistance, double y) {
		return y + Math.sin(targetAbsoluteBearing) * targetDistance;
	}
	
	@Override
	public void onRobotDeath(RobotDeathEvent e) {
		removeRobotFromMap(e.getName());
	}
	
	@Override
	public void onScannedRobot(ScannedRobotEvent e) {
		registerScannedRobot(e);
	}

	private void removeRobotFromMap(String name) {
		for (RobotModel scanned : radarMap.values()) {
			if (scanned.getName().equals(name)) {
				radarMap.remove(scanned.getName());
			}
		}
	}
	
	private void registerScannedRobot(ScannedRobotEvent event) {
		RobotModel robot = radarMap.get(event.getName());
		if (robot == null) {
			robot = new RobotModel();
			robot.setName(event.getName());
		}
		robot.setBearing(event.getBearing());
		robot.setBearingRadians(event.getBearingRadians());
		robot.setDistance(event.getDistance());
		robot.setEnergy(event.getEnergy());
		robot.setHeading(event.getHeading());
		robot.setHeadingRadians(event.getHeadingRadians());
		robot.setVelocity(event.getVelocity());
		robot.setLastTurnScanned(turn);
		radarMap.put(robot.getName(), robot);
	}
	
}
